 <script setup>
import { ref, reactive } from 'vue'
import { UploadFilled, Loading } from '@element-plus/icons-vue'
import apiZk from '../../../api/zk/index.js'
import { marked } from 'marked'
import PizZip from 'pizzip'
import Docxtemplater from 'docxtemplater'
// PDF相关状态
const pdfUrl = ref('')
const pdfFile = ref(null)
const isPdfLoading = ref(false)

// AI对话相关状态
const messages = ref([
  { role: 'assistant', content: '您好！请上传PDF文件，我将为您解答相关问题。', isThinking: false }
])
const inputMessage = ref('')
const isAiLoading = ref(false)
const isRequestAborted = ref(false) // 标记请求是否被主动停止
let abortController = null 

// 处理文件上传
const handleFileUpload = (file) => {
  // 使用 URL.createObjectURL 替代 FileReader.readAsDataURL 提高大文件处理性能
  const fileUrl = URL.createObjectURL(file)
  pdfUrl.value = fileUrl
  pdfFile.value = file

  //  调用病例质控接口
  sendMessageZk()
  return false // 阻止默认上传行为
}

// 移除PDF
const removePdf = () => {
  // 释放之前创建的对象URL以避免内存泄漏
  if (pdfUrl.value) {
    URL.revokeObjectURL(pdfUrl.value)
  }
  pdfUrl.value = ''
  pdfFile.value = null
}

// 病例质控
const sendMessageZk = async () => { 
  if (!pdfFile.value || isAiLoading.value) return
  const formData = new FormData()
  // 添加PDF文件
  formData.append('file', pdfFile.value) // pdfFile.value 是用户上传的文件对象
  // 重置output完成状态
  isRequestAborted.value = false
  isAiLoading.value = true
  // 添加用户消息
  messages.value.push({
    role: 'user',
    content: '生成质控报告'
  })

  // 添加AI思考中的消息
  messages.value.push({
    role: 'assistant',
    content: '',
    isThinking: true,
    responseTime: null, // 用于存储响应时间
    type:'质控报告',
    steps:[]
  })
  // 记录请求开始时间
  const startTime = Date.now()
  // 创建 AbortController 用于取消请求
  abortController = new AbortController()

  try {
    await apiZk.processZK(
      formData,
      (chunk) => {
        // 实时更新输出
        const data = chunk.trim().replace(/^data:/, "")
        if (data) {
          if (data.includes('task')){
            // 更新最后一条AI消息（更新step）
            const lastMessage = messages.value[messages.value.length - 1];
            if (lastMessage.role === 'assistant') {
              const stepJsons = parseMixedJSON(data)
              for (const stepItem of stepJsons) { 
                const step = stepItem;
                if(lastMessage.steps){
                  const stepSet = new Set()
                  for(const item of lastMessage.steps){ 
                    const itemName = item['task']  + '-' + item['result_name']
                    stepSet.add(itemName)
                  }
                  const stepName = step['task'] + '-' + step['result_name']
                  if(!stepSet.has(stepName)){
                    lastMessage.steps = [...lastMessage.steps, {
                      ...step,
                      show: false
                    }]
                  }else{                  
                    const currStep = lastMessage.steps.find(item => item.task === step.task && item.result_name === step.result_name) 
                    currStep.content += step.content
                    lastMessage.steps = [...lastMessage.steps]
                  }
                }else{
                  lastMessage.steps = [{
                    ...step,
                    show:false
                  }]
                } 
              }
            }
          }else{
            if (!data.includes("[DONE]")) {
              const trimmedData = data.trim().replace(/\\n/g, '\n')
              // 更新最后一条AI消息（只添加实际内容）
              const lastMessage = messages.value[messages.value.length - 1];
              if (lastMessage.role === 'assistant') {
                lastMessage.content += trimmedData
              }
            }else{            
              // 计算响应时间
              const endTime = Date.now();
              const responseTime = endTime - startTime;
              // 更新最后一条AI消息（去掉思考中状态，添加响应时间）
              const lastMessage = messages.value[messages.value.length - 1];
              if (lastMessage.role === 'assistant') {
                lastMessage.isThinking = false;
                lastMessage.responseTime = responseTime;
              }
            }
          }
        }
      },
      abortController.signal
    )
  } catch (error) {
    const endTime = Date.now();
    const responseTime = endTime - startTime;
    const lastMessage = messages.value[messages.value.length - 1];
    if (error.name === 'AbortError') {
      console.log('请求已被用户取消')
      if(lastMessage.role ==='assistant'){
        lastMessage.isThinking = false;
        lastMessage.content='\n[请求已被用户取消]'
        lastMessage.responseTime =responseTime;
      }
      isRequestAborted.value = true
    } else {
      console.error('Error:', error)
      if(lastMessage.role ==='assistant'){
        lastMessage.isThinking = false;
        lastMessage.content='抱歉，AI助手当前无法回应，请稍后再试。'
        lastMessage.responseTime =responseTime;
      }
    }
  } finally {
    console.log('请求结束')
    isAiLoading.value = false
    abortController = null
    const lastMessage = messages.value[messages.value.length - 1];
    lastMessage.isThinking = false;
  }
}
// 停止请求
const stopRequest = () => {
  if (abortController) {
    abortController.abort()
  }
}
// 分隔流式返回的json
function parseMixedJSON(str) {
  const result = [];
  let bracketCount = 0; // 计数方括号
  let braceCount = 0;   // 计数花括号
  let start = -1;
  
  // 首先尝试按 符号 分隔处理
  const lines = str.split('《》');
  for (const line of lines) {
    if (line.trim()) {
      try {
        result.push(JSON.parse(line.trim()));
      } catch (e) {
        // 如果按行解析失败，继续使用原有的字符级解析
        // 这里可以添加更详细的处理逻辑
      }
    }
  }
  
  // 如果按行分割解析成功，直接返回结果
  if (result.length > 0) {
    return result;
  }



  for (let i = 0; i < str.length; i++) {
    const char = str[i];
    
    if (char === '{' || char === '[') {
      if (braceCount === 0 && bracketCount === 0) {
        start = i;
      }
      if (char === '{') braceCount++;
      if (char === '[') bracketCount++;
    } else if (char === '}' || char === ']') {
      if (char === '}') braceCount--;
      if (char === ']') bracketCount--;
      
      if (braceCount === 0 && bracketCount === 0 && start !== -1) {
        const jsonStr = str.substring(start, i + 1);
        try{
          result.push(JSON.parse(jsonStr));
        } catch (error) {
          // console.error('解析失败:', error.message);
          if(jsonStr.length>0){
            const position = parseInt(error.message.split('JSON at position')[1].split('(line')[0].trim())

            const start = Math.min(0,position-5);
            const end = Math.min(jsonStr.length, position+5);

            // console.error('错误附近的字符:', jsonStr.substring(start, end));
          }
        }
      }
    }
  }
  
  return result;
}

// 用于渲染 Markdown 的方法
const renderMarkdown = (content) => {
  return marked(content)
}

// 发送消息到AI
const sendMessage = async () => {
  if (!inputMessage.value.trim() || isAiLoading.value) return

  // 添加用户消息
  messages.value.push({
    role: 'user',
    content: inputMessage.value
  })

  // 添加AI思考中的消息
  messages.value.push({
    role: 'assistant',
    content: '',
    isThinking: true,
    responseTime: null // 用于存储响应时间
  })

  // 清空输入框
  let userMessage = inputMessage.value
  inputMessage.value = ''
  isAiLoading.value = true

  // 记录请求开始时间
  const startTime = Date.now()

  // 判断用户对话中是否包含生成质控报告
  if (userMessage.includes('生成质控报告')) {
    console.log("生成质控报告")
    // 给userMessage 重新赋值
    userMessage = userMessage.replace('生成质控报告', '将下面内容调整成一个病历质检报告格式并输出，内容如下：（# 病历质控问题汇总报告\n' +
      '\n' +
      '根据对病历文档的全面质控审查，发现以下问题需引起关注。本汇总按问题类型分类，综合了各段落（包括首页、入院记录、病程记录、术前讨论记录、术前小结、术前讨论、手术记录、出院病情证明书、出院记录、临时医嘱、长期医嘱）中提取的质控问题，已合并同类项并过滤掉OCR提取导致的轻微格式问题。每个问题均标注涉及段落和严重程度，以协助医生优先整改。\n' +
      '\n' +
      '## 一、诊断信息不一致\n' +
      '**特征**：同一患者在不同记录中的诊断数量或内容存在矛盾。\n' +
      '\n' +
      '1. **房间隔缺损诊断类型不一致**  \n' +
      '   - **描述**：房间隔缺损的诊断类型在入院诊断、修正诊断、出院诊断和辅助检查中存在矛盾，包括多孔型、中央孔型、下腔型、混合型、双孔型、继发孔型等不同描述，且疾病编码（如Q21.100 vs Q21.102）不统一。  \n' +
      '   - **涉及段落**：首页、入院记录、病程记录、出院病情证明书、出院记录、全部信息点  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '2. **疾病编码重复或错误**  \n' +
      '   - **描述**：心房扩大和心室扩大使用了相同的疾病编码I51.700x00，但这是两种不同的心脏结构异常，应使用不同编码。  \n' +
      '   - **涉及段落**：首页  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '3. **入院病情评估矛盾**  \n' +
      '   - **描述**：心房扩大、心室扩大等诊断的入院病情记录为"无"或"情况不明"，但与先天性心脏病相关病情不符；出院诊断中部分并发症（如心肌酶谱异常、肺部感染）的入院病情记录不准确。  \n' +
      '   - **涉及段落**：首页、全部信息点  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '4. **诊断数量不一致**  \n' +
      '   - **描述**：查房诊断（如右心房增大、右心室扩大）与首次病程记录初步诊断的数量不一致，缺乏统一性。  \n' +
      '   - **涉及段落**：病程记录  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '5. **心肌酶谱异常诊断依据不严谨**  \n' +
      '   - **描述**：诊断依据中引用的肌酸激酶-MB亚型值（39.0U/L）有波动，但诊断维持性记录不够严谨，缺乏动态评估。  \n' +
      '   - **涉及段落**：病程记录  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '## 二、记录内容与医疗事实或逻辑不符\n' +
      '**特征**：记录的时间、内容与实际的医疗行为发生矛盾。\n' +
      '\n' +
      '1. **手术时间顺序异常**  \n' +
      '   - **描述**：房间隔缺损封堵术（2025-03-19）在体外循环辅助开放性心脏手术（2025-03-20）之前进行，对于需要体外循环的心脏手术，顺序可能不合理。  \n' +
      '   - **涉及段落**：首页  \n' +
      '   - **严重程度**：严重\n' +
      '\n' +
      '2. **手术级别与类型不匹配**  \n' +
      '   - **描述**：体外循环辅助开放性心脏手术作为重大心脏手术，手术级别标注为3级，但通常此类手术应为4级。  \n' +
      '   - **涉及段落**：首页  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '3. **患者年龄与手术适应症不符**  \n' +
      '   - **描述**：患者年龄9岁6个月进行房间隔缺损封堵术，与常规幼儿期干预的治疗时机可能不符。  \n' +
      '   - **涉及段落**：首页  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '4. **体格检查、现病史与诊断矛盾**  \n' +
      '   - **描述**：  \n' +
      '     - 体格检查显示双肺呼吸音清、无呼吸道症状，但诊断包含肺部感染、胸腔积液、气胸等严重呼吸系统疾病。  \n' +
      '     - 现病史描述患儿精神状态良好、无呕吐腹泻，但诊断包含电解质代谢紊乱、低钾血症、低钙血症。  \n' +
      '     - 心脏听诊有杂音与房间隔缺损相符，但诊断心肌酶谱异常缺乏临床表现支持。  \n' +
      '   - **涉及段落**：入院记录  \n' +
      '   - **严重程度**：严重（体格检查与诊断矛盾）、中等（其他）\n' +
      '\n' +
      '5. **检验值和时间记录矛盾**  \n' +
      '   - **描述**：  \n' +
      '     - 白细胞计数在主刀医师术前查房记录（0.66×10^9/L）与转科记录（5.66×10^9/L）中不一致。  \n' +
      '     - 患者性别在接收记录（男性）与其他记录（女性）中矛盾。  \n' +
      '     - 手术时间在手术记录（09:30-11:50）与转科记录（09:30-12:50）中不一致。  \n' +
      '   - **涉及段落**：病程记录  \n' +
      '   - **严重程度**：严重（白细胞计数和性别矛盾）、中等（手术时间矛盾）\n' +
      '\n' +
      '6. **诊断和时间逻辑错误**  \n' +
      '   - **描述**：  \n' +
      '     - 查房诊断中包含"房间隔缺损修补术后"，但手术尚未进行（手术于2025-03-20进行）。  \n' +
      '     - 术前讨论记录时间（2025-03-18 16:30）晚于记录创建时间（2025-03-19 07:52），或"明日"指代不明。  \n' +
      '   - **涉及段落**：病程记录、术前讨论记录  \n' +
      '   - **严重程度**：严重（诊断时间错误）、中等（讨论时间逻辑）\n' +
      '\n' +
      '7. **手术名称和术中所见不一致**  \n' +
      '   - **描述**：  \n' +
      '     - 术前讨论中病史摘要描述手术为"经皮房间隔缺损封堵术"，但讨论手术为"房间隔缺损修补术"，术式不符。  \n' +
      '     - 手术记录中术中所见为"多个筛孔型房缺"，但术前诊断为"中央孔型+下腔型"，分型不一致。  \n' +
      '   - **涉及段落**：术前讨论、手术记录  \n' +
      '   - **严重程度**：严重（手术名称不一致）、中等（术中所见与诊断不符）\n' +
      '\n' +
      '8. **检查结果与诊断矛盾**  \n' +
      '   - **描述**：X线检查显示"心肺未见异常"，但出院诊断包含肺部感染、胸腔积液、气胸，逻辑不符。  \n' +
      '   - **涉及段落**：出院病情证明书  \n' +
      '   - **严重程度**：严重\n' +
      '\n' +
      '9. **手术安排描述不符**  \n' +
      '   - **描述**：诊疗小结中手术安排描述"拟择期外科手术治疗"，但间隔仅1天（2025-03-19至2025-03-20），与"择期"含义不符。  \n' +
      '   - **涉及段落**：出院病情证明书  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '10. **出院转归与症状矛盾**  \n' +
      '    - **描述**：出院转归标注为"治愈"，但出院情况描述患者"活动后稍有胸闷、气促，咳嗽"，且需定期复查，与治愈状态不符。  \n' +
      '    - **涉及段落**：出院病情证明书、出院记录  \n' +
      '    - **严重程度**：中等\n' +
      '\n' +
      '11. **医嘱时间和内容矛盾**  \n' +
      '    - **描述**：  \n' +
      '      - 手术医嘱执行时间早于下达时间，或时间逻辑矛盾（如医嘱下达2025-03-18，执行2025-03-19）。  \n' +
      '      - 血制品输注医嘱单位不一致（去白细胞悬浮红细胞1u vs 执行记录200ml）。  \n' +
      '      - 长期医嘱中同时存在禁食和流质膳食、鼻导管吸氧和呼吸机辅助通气、一级护理和特级护理、病危和病重等矛盾内容。  \n' +
      '      - 长期医嘱中封管频率（每周一次）和血氧监测频率（每12小时一次）设置不合理。  \n' +
      '    - **涉及段落**：临时医嘱、长期医嘱  \n' +
      '    - **严重程度**：严重（时间逻辑矛盾）、中等（其他）\n' +
      '\n' +
      '## 三、医疗流程不合规或顺序混乱\n' +
      '**特征**：医疗文书的书写顺序或内容不符合医疗常规流程。\n' +
      '\n' +
      '1. **手术麻醉医师安排异常**  \n' +
      '   - **描述**：同一天（2025-03-19）进行的两台手术麻醉医师均为同一人，但手术时间重叠或衔接可能存在麻醉管理问题。  \n' +
      '   - **涉及段落**：首页  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '2. **修正诊断缺乏病程记录**  \n' +
      '   - **描述**：入院记录中包含多次修正诊断（2025-03-21和2025-03-27），但缺乏相应的病程记录说明修正原因和依据。  \n' +
      '   - **涉及段落**：入院记录  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '3. **术前检查与手术安排时间紧凑**  \n' +
      '   - **描述**：首次病程记录中诊疗计划同时安排"明日完善心脏介入手术"和多项检查（如血液分析、生化检查），时间紧凑，可能存在流程不合理。  \n' +
      '   - **涉及段落**：病程记录  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '4. **术前禁食和抗生素使用时机不当**  \n' +
      '   - **描述**：  \n' +
      '     - 术前禁食医嘱时间超过24小时，不符合术前禁食8小时的标准。  \n' +
      '     - 头孢唑林钠术前3小时使用，不符合术前30-60分钟预防性使用抗生素的常规。  \n' +
      '   - **涉及段落**：临时医嘱  \n' +
      '   - **严重程度**：严重\n' +
      '\n' +
      '5. **护理常规矛盾**  \n' +
      '   - **描述**：长期医嘱中同时存在"儿科护理常规"与"PICU护理常规"，护理标准不统一。  \n' +
      '   - **涉及段落**：长期医嘱  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '6. **出院诊断未反映术后状况**  \n' +
      '   - **描述**：房间隔缺损封堵术失败后行外科修补术，但出院诊断仍记录为"房间隔缺损（混合型）"，未能反映术后实际状况。  \n' +
      '   - **涉及段落**：出院记录  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '## 四、记录内容不完整或信息不全\n' +
      '**特征**：记录要素不全，未能完整反映病情或医疗过程。\n' +
      '\n' +
      '1. **手术信息不完整**  \n' +
      '   - **描述**：  \n' +
      '     - 手术记录中缺少手术具体时间、持续时间、术中出血量等关键参数。  \n' +
      '     - 手术名称"联合的右心和左心导管置"缺少关键描述词（如"入术"）。  \n' +
      '     - 手术记录中送验标本名称为空，但根据手术类型通常需送检组织标本。  \n' +
      '     - 手术记录中引流记录不明确（心包及纵隔引流数目为2，但未说明具体位置和数目）。  \n' +
      '     - 手术器械清点结果仅提到"清点纱布器械无误"，但未记录具体项目和数量。  \n' +
      '   - **涉及段落**：首页、手术记录  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '2. **抢救记录不完整**  \n' +
      '   - **描述**：抢救记录中未记录具体的抢救措施执行时间和药物使用剂量。  \n' +
      '   - **涉及段落**：病程记录  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '3. **辅助检查结果不完整**  \n' +
      '   - **描述**：术前讨论记录中辅助检查结果被截断（如血小板计数后内容不完整）。  \n' +
      '   - **涉及段落**：术前讨论记录  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '4. **术前小结信息缺失**  \n' +
      '   - **描述**：  \n' +
      '     - 助手字段为空，未填写助手医师信息。  \n' +
      '     - 术前风险评估等级未选择（低、中、高均未打勾）。  \n' +
      '     - 审签意见和上级医师签名字段为空。  \n' +
      '     - 病历摘要过于简单，未包含体征、检验等重要信息。  \n' +
      '     - 术前准备部分仅以表格形式列出，未系统描述。  \n' +
      '   - **涉及段落**：术前小结  \n' +
      '   - **严重程度**：中等（风险评估、审签、签名、病历摘要）、轻微（助手、术前准备）\n' +
      '\n' +
      '5. **讨论人员信息不完整**  \n' +
      '   - **描述**：术前讨论记录中未明确参与讨论人员的具体职称与科室对应关系。  \n' +
      '   - **涉及段落**：术前讨论  \n' +
      '   - **严重程度**：轻微\n' +
      '\n' +
      '6. **出院文档信息不完整**  \n' +
      '   - **描述**：  \n' +
      '     - X线检查日期不完整（仅显示"2025-03-1"）。  \n' +
      '     - 伤口愈合情况记录为"--"，未填写具体状态。  \n' +
      '   - **涉及段落**：出院病情证明书、出院记录  \n' +
      '   - **严重程度**：轻微\n' +
      '\n' +
      '7. **医嘱信息不完整**  \n' +
      '   - **描述**：  \n' +
      '     - 部分医嘱缺少执行者签名。  \n' +
      '     - 部分医嘱缺少具体用法用量（如"氯化钠注射液(NS50)"仅注明"封管用"）。  \n' +
      '     - 部分医嘱缺少剂量、用法或频率等信息。  \n' +
      '   - **涉及段落**：临时医嘱、长期医嘱  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '## 五、病历书写不规范、存在错误\n' +
      '**特征**：文字错误、格式错误、术语使用不当（已排除OCR导致的轻微格式问题）。\n' +
      '\n' +
      '1. **术语使用不规范**  \n' +
      '   - **描述**：  \n' +
      '     - 药品名称"氯化钠注射液(NS50)"不符合标准命名规范，应为"0.9%氯化钠注射液50ml"。  \n' +
      '     - 手术名称记录不规范，如"房间隔缺损修补术；体外循环辅助开放性心脏手术"分号使用不当。  \n' +
      '     - 诊断术语不一致，如出院诊断"房间隔缺损（混合型）"与超声检查"房间隔缺损（双孔型）"不统一。  \n' +
      '   - **涉及段落**：临时医嘱、手术记录、出院病情证明书  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '2. **记录内容错误**  \n' +
      '   - **描述**：  \n' +
      '     - 输血量记录为"1.5"，缺少单位（应注明"1.5单位"或具体毫升数）。  \n' +
      '     - 术前小结中年龄选项与患者实际年龄（9岁6月）不符，选项仅适用于成人。  \n' +
      '     - 出院转归记录为"治愈"，但诊疗经过描述"病情好转"，逻辑矛盾。  \n' +
      '   - **涉及段落**：手术记录、术前小结、出院记录  \n' +
      '   - **严重程度**：中等\n' +
      '\n' +
      '3. **文字错误**  \n' +
      '   - **描述**：诊疗小结中出现"同意同意"重复用词。  \n' +
      '   - **涉及段落**：出院病情证明书、出院记录  \n' +
      '   - **严重程度**：轻微\n' +
      '\n' +
      '---\n' +
      '\n' +
      '**总结说明**：  \n' +
      '- 本汇总基于各段落独立质控问题生成，未考虑段落间联动问题，但已合并跨段落的同类问题。  \n' +
      '- 严重程度定义：  \n' +
      '  - **严重**：可能直接影响医疗安全或病历真实性，需立即整改。  \n' +
      '  - **中等**：影响病历严谨性和完整性，需限期整改。  \n' +
      '  - **轻微**：影响文书规范性，建议整改。  \n' +
      '- 请医生根据上述问题逐一核对并修正，确保病历质量符合医疗文书规范及临床安全要求。）');
  }

  // 调用AI接口
  try {
    const url = 'https://api.siliconflow.cn/v1/chat/completions';
    const options = {
      method: 'POST',
      headers: {
        Authorization: 'Bearer sk-zlmxrwtzaiedpnrcgpvnnjufjzyxrfjpzyxjpzziurbhdnds',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        thinking_budget: 4096,
        top_p: 0.7,
        model: 'Qwen/Qwen2.5-72B-Instruct',
        messages: [{
          content: userMessage,
          role: 'user'
        }],
        stream: false // 确保一次性返回完整响应
      })
    };

    const response = await fetch(url, options);
    const data = await response.json();

    // 计算响应时间
    const endTime = Date.now();
    const responseTime = endTime - startTime;

    // 更新最后一条AI消息（去掉思考中状态，添加实际内容和响应时间）
    const lastMessage = messages.value[messages.value.length - 1];
    if (lastMessage.role === 'assistant') {
      lastMessage.isThinking = false;
      lastMessage.content = data.choices?.[0]?.message?.content || 'AI助手暂时无法回答您的问题，请稍后再试。';
      lastMessage.responseTime = responseTime;
    }
  } catch (error) {
    console.error(error);
    // 计算响应时间（即使出错也要记录）
    const endTime = Date.now();
    const responseTime = endTime - startTime;

    // 更新最后一条AI消息（去掉思考中状态，添加错误提示和响应时间）
    const lastMessage = messages.value[messages.value.length - 1];
    if (lastMessage.role === 'assistant') {
      lastMessage.isThinking = false;
      lastMessage.content = '抱歉，AI助手当前无法回应，请稍后再试。';
      lastMessage.responseTime = responseTime;
    }
  } finally {
    isAiLoading.value = false;
  }
}

// 处理拖拽上传
const handleDrop = (e) => {
  e.preventDefault()
  const files = e.dataTransfer.files
  if (files.length > 0 && files[0].type === 'application/pdf') {
    handleFileUpload(files[0])
  }
}

// 处理Element Plus上传组件的change事件
const handleChange = (uploadFile) => {
  if (uploadFile && uploadFile.raw) {
    handleFileUpload(uploadFile.raw)
  }
}

// 下载AI返回的文字内容
const downloadAIResponse = (content, index) => {
  const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.download = `AI回复_${index + 1}.md`;
  link.click();
  URL.revokeObjectURL(url);
}
// // 保存成txt
// const downloadSingleStep = (step, index) => {
//   const content = `# ${step.task}-${step.result_name}\n\n${step.content}`;
//   const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
//   const url = URL.createObjectURL(blob);
//   const link = document.createElement('a');
//   link.href = url;
//   link.download = `质控步骤_${index + 1}_${step.task}-${step.result_name}.txt`;
//   link.click();
//   URL.revokeObjectURL(url);
// }

const downloadSingleStep = async (step, index) => {
  try {
    // 准备发送到接口的数据
    const requestData = {
      text: step.content,
      filename: `${step.task}-${step.result_name}`
    };
    
    // 调用 str2docx 接口获取 DOCX 文件 Blob
    const blob = await apiZk.str2docx(requestData);
    
    // 创建下载链接并触发下载
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = `质控步骤_${index + 1}_${step.task}-${step.result_name}.docx`;
    link.click();
    URL.revokeObjectURL(url);
  } catch (error) {
    console.error('生成 DOCX 文档失败:', error);
    // 失败时提供备选方案 - 下载为文本文件
    const content = `${step.task}-${step.result_name}\n\n${step.content}`;
    const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = `质控步骤_${index + 1}_${step.task}-${step.result_name}.txt`;
    link.click();
    URL.revokeObjectURL(url);
  }
};

</script>

<template>
  <div class="pdf-ai-container">
    <!-- 左侧PDF查看区域 -->
    <div class="pdf-section">
      <div class="section-header">
        <h3>病历文档</h3>
      </div>
      <div
        class="pdf-content"
        @drop="handleDrop"
        @dragover.prevent
      >
        <!-- 上传区域 -->
        <div v-if="!pdfUrl" class="upload-area">
          <el-upload
            class="upload-demo"
            drag
            action="#"
            accept=".pdf"
            :auto-upload="false"
            :on-change="handleChange"
            :show-file-list="false"
          >
            <el-icon class="el-icon--upload">
              <UploadFilled />
            </el-icon>
            <div class="el-upload__text">
              将病历文件拖到此处，或<em>点击上传</em>
            </div>
            <template #tip>
              <div class="el-upload__tip">
                仅支持PDF格式文件，且不超过10MB
              </div>
            </template>
          </el-upload>
        </div>

        <!-- PDF显示区域 -->
        <div v-else class="pdf-viewer">
          <div class="pdf-toolbar">
            <el-button @click="removePdf" type="danger" size="small">
              移除PDF
            </el-button>
          </div>
          <iframe
            :src="pdfUrl"
            class="pdf-iframe"
            frameborder="0"
          ></iframe>
        </div>
      </div>
    </div>

    <!-- 右侧AI对话区域 -->
    <div class="ai-section">
      <div class="section-header">
        <h3>质控助手</h3>
      </div>
      <div class="ai-content">
        <!-- 消息显示区域 -->
        <div class="messages-container">
          <div
            v-for="(message, index) in messages"
            :key="index"
            :class="['message', message.role]"
          >
            <!-- AI助手头像 -->
            <div v-if="message.role === 'assistant'" class="avatar assistant-avatar">
              <img src="@/assets/images/avatar.png" alt="AI助手" />
            </div>

            <div class="message-content-wrapper">
              <div class="message-content">
                <!-- 用户消息 -->
                <div v-if="message.role === 'user'">
                  {{ message.content }}
                </div>

                <!-- AI助手消息 -->
                <div v-else-if="message.role === 'assistant'">
                  <div v-if="message.type && message.type === '质控报告'">
                    <div v-if="message.isThinking">
                      <el-icon class="is-loading"><Loading /></el-icon>
                      <div 
                        v-for="(step, index) in message.steps"
                        :key="index"
                        class="response-step-container"
                        @click="step.show = !step.show">
                        <div class="response-step-title">{{  step.task }}-{{  step.result_name }}</div>
                        <div v-if="step.show" class="response-step-content" v-html="renderMarkdown(step.content)"></div>
                      </div>
                      <div class="response-content" v-if="message.content">
                        {{ message.content }}
                      </div>
                    </div>
                    <div v-else>
                      <div class="response-info" v-if="message.responseTime">
                        响应时间: {{ message.responseTime }}ms
                      </div>
                      <div 
                        v-for="(step, index) in message.steps"
                        :key="index"
                        class="response-step-container"
                        >
                        <div class="response-step-title" @click="step.show = !step.show">     
                          <el-button
                            type="primary"
                            size="small"
                            @click.stop="downloadSingleStep(step, index)"
                            plain
                            style="margin-left: 10px; float: right;"
                          >
                            下载
                          </el-button>
                          {{  step.task }}-{{  step.result_name }}</div>
                        <div v-if="step.show" class="response-step-content" @click="step.show = !step.show" v-html="renderMarkdown(step.content)"></div>
                      </div>
                      <div class="response-content" v-if="message.content">
                        {{ message.content }}
                      </div>
                    </div>
                  </div>
                  <div v-else>
                    <div v-if="message.isThinking" class="thinking-process">
                      <el-icon class="is-loading"><Loading /></el-icon>
                      <span>思考中...</span>
                      <div class="response-content">
                        {{ message.content }}
                      </div>
                    </div>
                    <div v-else>
                      <div class="response-info" v-if="message.responseTime">
                        响应时间: {{ message.responseTime }}ms
                      </div>
                      <div class="response-content">
                        {{ message.content }}
                      </div>
                      <!-- 下载按钮 -->
                      <div class="download-button">
                        <el-button
                          type="primary"
                          size="small"
                          @click="downloadAIResponse(message.content, index)"
                          plain
                        >
                          下载回复
                        </el-button>
                      </div>
                    </div>
                  </div>

                </div>
              </div>
            </div>

            <!-- 用户头像（已移除） -->
            <!-- <div v-if="message.role === 'user'" class="avatar user-avatar">
              <img src="@/assets/images/avatar.png" alt="用户" />
            </div> -->
          </div>
        </div>

        <!-- 输入区域 -->
        <div class="input-container">
          <el-input
            v-model="inputMessage"
            type="textarea"
            :rows="3"
            placeholder="请输入您的问题..."
            :disabled="isAiLoading || !pdfUrl"
          />
          <div class="input-actions">
            <el-button
              type="primary"
              @click="sendMessage"
              :loading="isAiLoading"
              :disabled="!pdfUrl"
            >
              发送
            </el-button>

            <el-button @click="stopRequest" :disabled="!isAiLoading" style="margin-left: 10px;">停止</el-button>

          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">

.pdf-ai-container {
  display: flex;
  height: calc(100vh - 100px);
  padding: 20px;
  gap: 20px;

  .pdf-section, .ai-section {
    display: flex;
    flex-direction: column;
    background: #fff;
    border-radius: 8px;
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);

    .section-header {
      padding: 16px 20px;
      border-bottom: 1px solid #eee;

      h3 {
        margin: 0;
        font-size: 18px;
        font-weight: 600;
        color: #333;
      }
    }
  }

  /* 左侧PDF区域 */
  .pdf-section {
    flex: 7;

    .pdf-content {
      flex: 1;
      padding: 20px;
      overflow: auto;

      .upload-area {
        display: flex;
        align-items: center;
        justify-content: center;
        height: 100%;

        :deep(.el-upload) {
          width: 100%;
        }

        :deep(.el-upload-dragger) {
          width: 100%;
          height: 300px;
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
        }
      }

      .pdf-viewer {
        height: 100%;
        display: flex;
        flex-direction: column;

        .pdf-toolbar {
          padding: 10px 0;
        }

        .pdf-iframe {
          flex: 1;
          width: 100%;
          min-height: 500px;
        }
      }
    }
  }

  /* 右侧AI区域 */
  .ai-section {
    flex: 3;
    display: flex;
    flex-direction: column;
    overflow: hidden; /* 隐藏超出部分 */

    .section-header {
      padding: 16px 20px;
      border-bottom: 1px solid #eee;
      flex-shrink: 0; /* 防止头部被压缩 */

      h3 {
        margin: 0;
        font-size: 18px;
        font-weight: 600;
        color: #333;
      }
    }

    .ai-content {
      flex: 1;
      display: flex;
      flex-direction: column;
      overflow: hidden; /* 隐藏超出部分 */

      .messages-container {
        flex: 1;
        padding: 20px;
        overflow-y: auto; /* 允许垂直滚动 */
        display: flex;
        flex-direction: column;

        /* 确保消息从上到下排列 */
        justify-content: flex-start;

        .message {
          display: flex;
          margin-bottom: 16px;
          align-items: flex-start;
          flex-shrink: 0; /* 防止消息项被压缩 */

          .avatar {
            flex-shrink: 0;
            width: 36px;
            height: 36px;
            border-radius: 50%;
            overflow: hidden;
            background-color: #f0f0f0;
            display: flex;
            align-items: center;
            justify-content: center;

            img {
              width: 100%;
              height: 100%;
              object-fit: cover;
            }

            &.assistant-avatar {
              margin-right: 12px;
              background-color: #67c23a;
              color: white;
            }
          }

          .message-content-wrapper {
            flex: 1;
            display: flex;
            flex-direction: column;
            max-width: calc(100% - 40px);
            .message-content {
              padding: 12px 16px;
              border-radius: 8px;
              line-height: 1.5;
              max-width: calc(100% - 40px);
              word-wrap: break-word;
              overflow-wrap: break-word;
              white-space: pre-wrap;
              overflow-y: auto;
              // max-height: 300px;

              .thinking-process {
                display: flex;
                align-items: center;
                gap: 8px;
                max-width: calc(100% - 32px);
              }

              .response-info {
                font-size: 12px;
                color: #999;
                margin-bottom: 5px;
              }

              .response-content {
                max-width: 100%;
                margin-bottom: 10px;
              }

              .download-button {
                margin-top: 10px;
              }

              .response-step-container {
                display: flex;
                flex-direction: column;
                gap: 0;
                margin-bottom: 15px;
                width: 100%;
                border: 1px solid #dcdfe6;
                border-radius: 6px;
                overflow: hidden;
                .response-step-title {
                  background-color: #f0f8ff;
                  padding: 12px 16px;
                  border-bottom: 1px solid #dcdfe6;
                  cursor: pointer;
                  width: 100%;
                  box-sizing: border-box;
                  font-weight: 500;
                  color: #333;
                  transition: background-color 0.3s;
                  
                  &:hover {
                    background-color: #e6f4ff;
                  }
                  
                  &::before {
                    content: "▶";
                    margin-right: 8px;
                    transition: transform 0.3s;
                    display: inline-block;
                  }
                  
                  &.active::before {
                    transform: rotate(90deg);
                  }
                }
                
                .response-step-content {
                  background-color: #fafafa;
                  padding: 15px;
                  width: 100%;
                  box-sizing: border-box;
                  font-size: 14px;
                  line-height: 1.6;
                  white-space: pre-wrap;
                }
              }
            }
          }

          &.user {
            flex-direction: row-reverse;

            .message-content-wrapper {
              align-items: flex-end;

              .message-content {
                background-color: #409eff;
                color: white;
                margin-left: auto; /* 使用户消息靠右对齐 */
              }
            }
          }

          &.assistant {
            .message-content-wrapper {
              align-items: flex-start;

              .message-content {
                background-color: #f5f5f5;
                color: #333;
              }
            }
          }
        }
      }

      .input-container {
        padding: 0 20px 20px;
        flex-shrink: 0; /* 防止输入区域被压缩 */

        .input-actions {
          margin-top: 12px;
          display: flex;
          justify-content: flex-end;
        }
      }
    }
  }
}
</style>
